package com.lambkit.plugin.redis;

import cn.hutool.db.nosql.redis.RedisDS;
import com.lambkit.plugin.redis.serializer.ISerializer;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.util.SafeEncoder;

import java.util.*;

/**
 * @author yangyong(孤竹行)
 */
public class RedisCache {
    private RedisDS redisDS;
    private ISerializer serializer;

    public RedisCache(RedisDS redisDS, ISerializer serializer) {
        this.redisDS = redisDS;
        this.serializer = serializer;
    }

    public Jedis getJedis() {
        return this.redisDS.getJedis();
    }

    public void close() {
        this.redisDS.close();
    }

    public <T> T get(Object key) {
        return (T) valueFromBytes(getJedis().get(keyToBytes(key)));
    }

    public Collection<? extends String> keys(String pattern) {
        return getJedis().keys(pattern);
    }

    public void set(Object key, Object value) {
        getJedis().set(keyToBytes(key), valueToBytes(value));
    }

    public void del(Object key) {
        getJedis().del(keyToBytes(key));
    }

    public void setex(Object key, long liveSeconds, Object value) {
        getJedis().setex(keyToBytes(key), liveSeconds, valueToBytes(value));
    }

    public Long expire(Object key, long seconds) {
        return getJedis().expire(keyToBytes(key), seconds);
    }

    public Long ttl(Object key) {
        return getJedis().ttl(keyToBytes(key));
    }

    public void lpush(Object key, Object... values) {
        getJedis().lpush(keyToBytes(key), valuesToBytesArray(values));
    }

    public Long llen(Object key) {
        return getJedis().llen(keyToBytes(key));
    }

    public void lrem(Object key, long count, Object value) {
        getJedis().lrem(keyToBytes(key), count, valueToBytes(value));
    }

    public List lrange(Object key, long start, long end) {
        return valueListFromBytesList(getJedis().lrange(keyToBytes(key), start, end));
    }

    public void srem(Object key, Object... members) {
        getJedis().srem(keyToBytes(key), valuesToBytesArray(members));
    }

    public Set smembers(Object key) {
        return valueListFromBytesSet(getJedis().smembers(keyToBytes(key)));
    }

    public Long scard(Object key) {
        return getJedis().scard(keyToBytes(key));
    }

    public Long sadd(Object key, Object... members) {
        return getJedis().sadd(keyToBytes(key), valuesToBytesArray(members));
    }

    public <T> T hget(Object key, Object field) {
        return (T) valueFromBytes(getJedis().hget(keyToBytes(key), keyToBytes(field)));
    }

    public void hset(Object key, Object field, Object value) {
        getJedis().hset(keyToBytes(key), keyToBytes(field), valueToBytes(value));
    }

    public Long hlen(String key) {
        return getJedis().hlen(keyToBytes(key));
    }

    public Collection<Object> hkeys(String key) {
        return valueListFromBytesSet(getJedis().hkeys(keyToBytes(key)));
    }

    public Collection hvals(String key) {
        return valueListFromBytesList(getJedis().hvals(keyToBytes(key)));
    }

    public Map hgetAll(String key) {
        return valueListFromBytesMap(getJedis().hgetAll(keyToBytes(key)));
    }

    public void hdel(Object key, Object field) {
        getJedis().hdel(keyToBytes(key), keyToBytes(field));
    }

    public void hdel(Object key) {
        getJedis().hdel(keyToBytes(key));
    }

    protected byte[] keyToBytes(Object key) {
        return SafeEncoder.encode(key.toString());
    }

    protected Object keyFromBytes(byte[] bytes) {
        return SafeEncoder.encode(bytes);
    }

    protected byte[] valueToBytes(Object value) {
        return this.serializer.serialize(value);
    }

    protected Object valueFromBytes(byte[] bytes) {
        return this.serializer.deserialize(bytes);
    }

    protected byte[][] valuesToBytesArray(Object... valuesArray) {
        byte[][] data = new byte[valuesArray.length][];
        for(int i = 0; i < data.length; ++i) {
            data[i] = this.valueToBytes(valuesArray[i]);
        }
        return data;
    }

    protected List valueListFromBytesList(List<byte[]> data) {
        List<Object> result = new ArrayList();
        Iterator iterator = data.iterator();
        while(iterator.hasNext()) {
            byte[] d = (byte[])iterator.next();
            result.add(this.valueFromBytes(d));
        }
        return result;
    }

    protected Set valueListFromBytesSet(Set<byte[]> data) {
        Set<Object> result = new HashSet<>();
        Iterator iterator = data.iterator();
        while(iterator.hasNext()) {
            byte[] d = (byte[])iterator.next();
            result.add(this.valueFromBytes(d));
        }
        return result;
    }

    private Map valueListFromBytesMap(Map<byte[],byte[]> data) {
        Map<Object, Object> result = new HashMap();
        if (data != null) {
            Iterator iterator = data.entrySet().iterator();
            while(iterator.hasNext()) {
                Map.Entry<byte[], byte[]> e = (Map.Entry)iterator.next();
                result.put(keyFromBytes((byte[])e.getKey()), valueFromBytes((byte[])e.getValue()));
            }
        }
        return result;
    }
}
